/**
 * Copyright (c) 2004, Jan Kneschke, incremental
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * - Redistributions of source code must retain the above copyright notice,
 *   this list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of the 'incremental' nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 * THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FN_ARRAY_H
#define FN_ARRAY_H

#include <stdlib.h>
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_PCRE_H
# include <pcre.h>
#endif
#include "buffer.h"

#ifdef __cplusplus
extern "C" {
#endif

#define DATA_IS_STRING(x) (x->type == TYPE_STRING)

typedef enum { TYPE_UNSET, TYPE_STRING, TYPE_COUNT, TYPE_ARRAY, TYPE_INTEGER, TYPE_FASTCGI, TYPE_CONFIG } data_type_t;
#define DATA_UNSET \
    data_type_t type; \
    conf_buffer *key; \
    int is_index_key; /* 1 if key is a array index (autogenerated keys) */ \
    struct data_unset *(*copy)(const struct data_unset *src); \
    void (* free)(struct data_unset *p); \
    void (* reset)(struct data_unset *p); \
    int (*insert_dup)(struct data_unset *dst, struct data_unset *src); \
    void (*print)(const struct data_unset *p, int depth)

typedef struct data_unset {
    DATA_UNSET;
} data_unset;

typedef struct {
    data_unset  **data;

    size_t *sorted;

    size_t used;
    size_t size;

    size_t unique_ndx;

    size_t next_power_of_2;
    int is_weakref; /* data is weakref, don't bother the data */
} array;

typedef struct {
    DATA_UNSET;

    int count;
} data_count;

typedef struct {
    DATA_UNSET;

    conf_buffer *value;
} data_string;

data_string *data_string_init(void);

typedef struct {
    DATA_UNSET;

    array *value;
} data_array;

data_array *data_array_init(void);

/**
 * possible compare ops in the configfile parser
 */
typedef enum {
    CONFIG_COND_UNSET,
    CONFIG_COND_EQ,      /** == */
    CONFIG_COND_MATCH,   /** =~ */
    CONFIG_COND_NE,      /** != */
    CONFIG_COND_NOMATCH  /** !~ */
} config_cond_t;

/**
 * possible fields to match against
 */
typedef enum {
    COMP_UNSET,
    COMP_SERVER_SOCKET,
    COMP_HTTP_URL,
    COMP_HTTP_HOST,
    COMP_HTTP_REFERER,
    COMP_HTTP_USERAGENT,
    COMP_HTTP_COOKIE,
    COMP_HTTP_REMOTEIP,
    COMP_HTTP_QUERYSTRING,

    COMP_LAST_ELEMENT
} comp_key_t;

/* $HTTP["host"] ==    "incremental.home.kneschke.de" { ... }
 * for print:   comp_key      op    string
 * for compare: comp          cond  string/regex
 */

typedef struct _data_config data_config;
struct _data_config {
    DATA_UNSET;

    array *value;

    conf_buffer *comp_key;
    comp_key_t comp;

    config_cond_t cond;
    conf_buffer *op;

    int context_ndx; /* more or less like an id */
    array *childs;
    /* nested */
    data_config *parent;
    /* for chaining only */
    data_config *prev;
    data_config *next;

    conf_buffer *string;
#ifdef HAVE_PCRE_H
    pcre   *regex;
    pcre_extra *regex_study;
#endif
};

data_config *data_config_init(void);

typedef struct {
    DATA_UNSET;

    int value;
} data_integer;

data_integer *data_integer_init(void);

array *array_init(void);
array *array_init_array(array *a);
void array_free(array *a);
void array_reset(array *a);
int array_insert_unique(array *a, data_unset *str);
data_unset *array_pop(array *a);
int array_print(array *a, int depth);
data_unset *array_get_element(array *a, const char *key);
data_unset *array_replace(array *a, data_unset *du);
int array_strcasecmp(const char *a, size_t a_len, const char *b, size_t b_len);
void array_print_indent(int depth);
size_t array_get_max_key_length(array *a);


#ifdef __cplusplus
}
#endif


#endif // FN_ARRAY_H
